using System;
using System.Collections.Generic;
using System.Text;

using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;

using System.ComponentModel;
using System.Threading;

using System.Diagnostics;
using System.Security.Permissions;

namespace Antix.Mail.Smtp.ServerForDevelopers
{
    class Server : ApplicationContext
    {
        #region Constructor

        public Server()
        {
            _ControlPanelForm = new ControlPanelForm();
            _ControlPanelForm.Load += new EventHandler(_ControlPanelForm_Load);
            _ControlPanelForm.Closing += new System.ComponentModel.CancelEventHandler(ControlPanelForm_Closing);

            _ControlPanelForm.Show();
        }

        #endregion

        #region Properties

        private TcpListener _Listener;
        private ControlPanelForm _ControlPanelForm;
        private delegate void SetStatusDelegate(string value);

        #endregion

        #region Methods

        public void Connect()
        {
            //_Listener = new TcpListener(
            //        new System.Net.IPAddress(new byte[] { 127, 0, 0, 1 }), 25);
            _Listener = new TcpListener(System.Net.IPAddress.Any, 25);
            try
            {
                _Listener.Start();
                while (_Listener != null)
                {
                    // wait for incomming message
                    Session session = new Session(_Listener);

                    // catch events
                    session.Connected += new EventHandler(Session_Connected);
                    session.MessageReceived += new EventHandler<MessageEventArgs>(Session_MessageReceived);
                    session.Disconnected += new EventHandler(Session_Disconnected);

                    // connect
                    session.Connect();
                }
            }
            catch (Exception ex)
            {
                SetStatus(string.Format("Error: {0}", ex.Message));
            }

            //ExitThread();
        }

        private void SetStatus(string status)
        {
            try
            {
                _ControlPanelForm.Invoke(new SetStatusDelegate(_ControlPanelForm.SetStatus),
                    new object[] { status });
            }
            // ignore errors trying to set the status
            catch (Exception) { }
        }

        #region Session Events

        void Session_Connected(object sender, EventArgs e)
        {
            SetStatus("Waiting");
        }

        void Session_Disconnected(object sender, EventArgs e)
        {
            SetStatus("Disconnected");
        }

        void Session_MessageReceived(object sender, MessageEventArgs e)
        {
            // make sure the subject isn't to long
            string subject = TextFunctions.Remove(e.Subject, Path.GetInvalidFileNameChars());
            if (subject.Length > 100) subject = string.Concat(subject.Substring(0, 100), " ...");
            string filePath = string.Format("{0}\\{1} ({2}).eml", Application.UserAppDataPath, subject, e.MessageId);

            //// Check permission
            FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Write, filePath);
            permission.Assert();

            // Save the message in the pickup directory
            StreamWriter file
                = File.CreateText(filePath);
            try
            {
                file.Write(e.Data);
                file.Close();

                SetStatus(String.Format("Recieved: {0}", e.Subject));
            }
            finally { file.Close(); }
        }

        #endregion

        #region ControlPanelForm Events

        void _ControlPanelForm_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(new ThreadStart(Connect));
            thread.Start();
        }

        void ControlPanelForm_Closing(object sender, CancelEventArgs e)
        {
            _Listener.Stop();
            _Listener = null;

            ExitThread();
        }

        #endregion

        #endregion
    }
}